import logging
import json
import datetime
from django.shortcuts import render
from django_redis import get_redis_connection
from django import http
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
from decimal import Decimal
from django.db import transaction
from django.core.paginator import Paginator, EmptyPage

from goods.models import SKU
from meiduo_mall.utils.views import LoginRequiredJSONMixin
from users.models import Address
from meiduo_mall.utils.response_code import RETCODE
from .models import OrderGoods, OrderInfo
# Create your views here.

logger = logging.getLogger('django')


class UserOrderInfoView(LoginRequiredMixin, View):
    """我的订单"""

    def get(self, request, page_num):
        """提供我的订单页面"""
        user = request.user
        # 查询订单
        orders = user.orderinfo_set.all().order_by("-create_time")
        # 遍历所有订单
        for order in orders:
            # 绑定订单状态
            order.status_name = OrderInfo.ORDER_STATUS_CHOICES[order.status-1][1]
            # 绑定支付方式
            order.pay_method_name = OrderInfo.PAY_METHOD_CHOICES[order.pay_method-1][1]
            order.sku_list = []
            # 查询订单商品
            order_goods = order.skus.all()
            # 遍历订单商品
            for order_good in order_goods:
                sku = order_good.sku
                sku.count = order_good.count
                sku.amount = sku.price * sku.count
                order.sku_list.append(sku)

        # 分页
        page_num = int(page_num)
        try:
            paginator = Paginator(orders, 3)
            page_orders = paginator.page(page_num)
            total_page = paginator.num_pages
        except EmptyPage:
            return http.HttpResponseNotFound('订单不存在')

        context = {
            "page_orders": page_orders,
            'total_page': total_page,
            'page_num': page_num,
        }
        return render(request, "user_center_order.html", context)


class OrderSuccessView(LoginRequiredMixin, View):
    """提交订单成功"""

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id':order_id,
            'payment_amount':payment_amount,
            'pay_method':pay_method
        }
        return render(request, 'order_success.html', context)


class OrderCommitView(LoginRequiredJSONMixin, View):
    """订单提交"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 接收参数
        json_data = json.loads(request.body.decode())
        address_id = json_data.get('address_id')
        pay_method = json_data.get('pay_method')

        # 校验参数
        if not all([address_id, pay_method]):
            return http.HttpResponseForbidden('缺少必传参数')
        try:
            address = Address.objects.get(id=address_id)
        except Address.DoesNotExist:
            return http.HttpResponseForbidden('不存在的地址')
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.HttpResponseForbidden('支付方式有误')

        # 存储订单信息
        # 创建order_id
        order_id = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '%09d' % request.user.id
        with transaction.atomic():  # 开启事物
            # 创建保存点
            save_id = transaction.savepoint()
            try:  # 暴力回滚
                order_info = OrderInfo.objects.create(
                    order_id=order_id,
                    user=request.user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal(0.00),
                    freight=Decimal(10.00),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )

                # 存储订单商品信息
                # 读取redis购物车中的数据
                redis_conn = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_{}'.format(request.user.id))
                redis_selected = redis_conn.smembers('selected_{}'.format(request.user.id))
                # 获取sku信息并存储
                for selected_sku_id in redis_selected:  # 不能一次性将购物车中的各种商品一块查出来，因为当前可能会有不同用户同时购买该商品，会导致sku中的stock, sales实时变化
                    while True:
                        sku = SKU.objects.get(id=selected_sku_id.decode())
                        origin_stock = sku.stock  # 该商品的初始库存
                        origin_sales = sku.sales  # 该商品的初始销量
                        # count = redis_cart[selected_sku_id].decode()  # 购物车中购买的数量
                        count = int(redis_cart[selected_sku_id])  # encode和decode操作都是对字符串进行的操作，如果原来数字字符串被encode后可以使用int()直接转为int
                        if count <= origin_stock:  # 如果购买的数量不多于库存就可以购买
                            new_stock = origin_stock - count  # sku中即将更新的stock
                            new_sales = origin_sales + count  # sku中即将更新的sales
                            # 使用乐观锁更新sku信息
                            result = SKU.objects.filter(
                                id=sku.id,
                                stock=origin_stock,
                                sales=origin_sales
                            ).update(
                                stock=new_stock,
                                sales=new_sales
                            )

                            if result == 0:  # 说明未更新成功，但是库存量充足，还可以继续下单
                                continue

                            # 订单记录成功，销量增加，库存减少
                            # sku.stock -= count
                            # sku.sales += count
                            # sku.save()
                            sku.spu.sales += count
                            sku.spu.save()

                            order_goods = OrderGoods.objects.create(
                                order=order_info,
                                sku=sku,
                                count=count,
                                price=sku.price
                            )

                            order_info.total_count += count
                            order_info.total_amount += count * sku.price

                            # 更新完成，跳出循环
                            break
                        else:  # 如果需求量大于库存，那么就回滚，防止产生脏数据
                            transaction.savepoint_rollback(save_id)
                            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

                    order_info.total_amount += order_info.freight
                    order_info.save()
            except Exception as e:
                logger.error(e)
                # 发生异常回滚
                transaction.savepoint_rollback(save_id)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

            # 提交事物
            transaction.savepoint_commit(save_id)

            # 清除redis中的缓存
            pl = redis_conn.pipeline()
            pl.hdel('carts_{}'.format(request.user.id), *redis_selected)
            pl.srem('selected_{}'.format(request.user.id), * redis_selected)
            pl.execute()

        # 返回响应
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'order_id': order_info.order_id})


class OrderSettlementView(LoginRequiredMixin, View):
    """获取订单页面视图"""
    def get(self, request):
        """
        {
            'user':,
            'addresses': [
                {
                    'id':,
                    'province':,
                    'city':,
                    'district':,
                    'receiver':,
                    'mobile':,
                },
                ...
            ],
            'skus': [
                {
                    'id':,
                    'default_image_url':,
                    'name':,
                    'price':,
                    'count':,
                    'amount':,
                },
                ...
            ],
            'total_count':,
            'total_amount':,
            'freight':,
            'payment_amount':
        }
        """
        # 获取登录用户
        user = request.user

        # 获取登录用户的收货地址
        try:
            default_address = user.default_address
            addresses = [default_address]
            other_addresses = user.addresses.filter(~Q(id=user.default_address.id), is_deleted=False)
            addresses.extend([address for address in other_addresses])
            # # 构建收货地址数据结构
            # addresses = [
            #     {
            #         'id': default_address.id,
            #         'province': default_address.province,
            #         'city': default_address.city,
            #         'district': default_address.district,
            #         'receiver': default_address.receiver,
            #         'mobile': default_address.mobile
            #     }
            # ]
            # for address in other_addresses:
            #     addresses.append({
            #         'id': address.id,
            #         'province': address.province,
            #         'city': address.city,
            #         'district': address.district,
            #         'receiver': address.receiver,
            #         'mobile': address.mobile
            #     })
        except Exception as e:
            logger.error(e)
            addresses = []  # 查询错误要返回控列表，让用户再编辑一个地址
            return http.HttpResponseServerError('读取地址失败')

        # 读取redis中的购物车信息,构建商品的数据结构
        redis_conn = get_redis_connection('carts')
        carts = redis_conn.hgetall('carts_{}'.format(user.id))
        selected = [cur_id.decode() for cur_id in redis_conn.smembers('selected_{}'.format(user.id))]
        # sku_list = []
        try:
            total_count = 0
            total_amount = Decimal(0.0)  # 金钱要用decimal类型
            skus = SKU.objects.filter(id__in=selected)
            for sku in skus:
                cur_count = carts[str(sku.id).encode()].decode()
                cur_amount = int(carts[str(sku.id).encode()].decode()) * sku.price
                # sku_list.append({
                #     'id': sku.id,
                #     'default_image': sku.default_image,
                #     'name': sku.name,
                #     'price': str(sku.price),
                #     'count': cur_count,
                #     'amount': str(cur_amount)
                # })
                sku.count = cur_count  # 可以直接给对象赋予属性
                sku.amount = cur_amount
                total_count += int(cur_count)
                total_amount += cur_amount
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError('查询数失败')

        # 构建上下文
        context = {
            'user': user,
            'addresses': addresses if addresses else [],
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': Decimal(10.00),
            'payment_amount': total_amount + 10
        }
        # 返回结果
        return render(request, 'place_order.html', context=context)

